﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Modbus.Device;
using PLCNET5_11_9.Data;
using S7.Net;
using S7.Net.Types;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.IO.Ports;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace PLCNET5_11_9.ViewModel
{    
    public class MainViewModel : ObservableObject
    {
        private SerialPort serialPort = new SerialPort();
        //private ModbusSerialMaster master = null;
        private ModbusIpMaster master = null;
        private Task rotobTaskT = null;
        private CancellationTokenSource cts = new CancellationTokenSource();
        private Queue<BKCommand> queue = new Queue<BKCommand>();

        //注意2个文件必须拷贝到EXE文件目录下..
        public static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

        //获取资源自动
        public ResourceDictionary resources { get; set; } = null;

        public int BtnWith { get; set; } = 50;
        public int BtnHight { get; set; } = 50;
        public MainModel mainModel { get; set; } = new MainModel();        
        public ObservableCollection<Item> ListBoxData { get; set; } = new ObservableCollection<Item>();

        private Plc plc31 = new Plc(CpuType.S7200Smart, "192.168.2.31", 0, 1);        
        private Plc plc33 = new Plc(CpuType.S7200Smart, "192.168.2.33", 0, 1);
        private Plc plc35 = new Plc(CpuType.S7200Smart, "192.168.2.35", 0, 1);
        private Plc plc37 = new Plc(CpuType.S7200Smart, "192.168.2.37", 0, 1);
        
        public ICommand Command75_1 { get; set; }        
        public ICommand Command75_2 { get; set; }
        public ICommand Command75_3 { get; set; }
        public ICommand Command75_4 { get; set; }
        public ICommand Command75_5 { get; set; }
        public ICommand Command75_6 { get; set; }
        public ICommand Command20_1 { get; set; }
        public ICommand Command20_2 { get; set; }
        public ICommand Command20_3 { get; set; }
        public ICommand Command20_4 { get; set; }
        public ICommand Command20_5 { get; set; }
        public ICommand Command20_6 { get; set; }
        public ICommand Command20T_1 { get; set; }
        public ICommand Command20T_2 { get; set; }
        public ICommand Command20T_3 { get; set; }
        public ICommand Command20T_4 { get; set; }
        public ICommand Command20T_5 { get; set; }
        public ICommand Command20T_6 { get; set; }
        public ICommand Command20T_7 { get; set; }
        public ICommand Command20T_8 { get; set; }
        public ICommand Command30T_8 { get; set; }

        
        public ICommand CommandZB_1 { get; set; }
        public ICommand CommandZB_2 { get; set; }
        public ICommand CommandZCB_1 { get; set; }
        public ICommand CommandZCB_2 { get; set; }
        public ICommand CommandDNBC_1 { get; set; }
        public ICommand CommandDNBC_2 { get; set; }
        public ICommand CommandDNBC_3 { get; set; }
        public ICommand CommandDNBC_4 { get; set; }
        public ICommand CommandDK_1 { get; set; }
        public ICommand CommandDK_2 { get; set; }
        public ICommand CommandQF_1 { get; set; }
        public ICommand CommandQF_2 { get; set; }
        public ICommand CommandQF_3 { get; set; }
        public ICommand CommandQF_4 { get; set; }
        public ICommand CommandQF_5 { get; set; }
        public ICommand CommandQF_6 { get; set; }

        public ICommand CommandGW1_1 { get; set; }
        public ICommand CommandGW1_2 { get; set; }
        public ICommand CommandGW1_3 { get; set; }
        public ICommand CommandGW1_4 { get; set; }
        public ICommand CommandGW2_1 { get; set; }
        public ICommand CommandGW2_2 { get; set; }
        public ICommand CommandGW2_3 { get; set; }
        public ICommand CommandGW2_4 { get; set; }
        public ICommand CommandGW3_1 { get; set; }
        public ICommand CommandGW3_2 { get; set; }
        public ICommand CommandGW3_3 { get; set; }
        public ICommand CommandGW3_4 { get; set; }


        public MainViewModel()
        {            
            Command75_1 = new RelayCommand<object>(DoCommand75_1);
            Command75_2 = new RelayCommand<object>(DoCommand75_2);
            Command75_3 = new RelayCommand<object>(DoCommand75_3);
            Command75_4 = new RelayCommand<object>(DoCommand75_4);
            Command75_5 = new RelayCommand<object>(DoCommand75_5);
            Command75_6 = new RelayCommand<object>(DoCommand75_6);
            Command20_1 = new RelayCommand<object>(DoCommand20_1);
            Command20_2 = new RelayCommand<object>(DoCommand20_2);
            Command20_3 = new RelayCommand<object>(DoCommand20_3);
            Command20_4 = new RelayCommand<object>(DoCommand20_4);
            Command20_5 = new RelayCommand<object>(DoCommand20_5);
            Command20_6 = new RelayCommand<object>(DoCommand20_6);
            Command20T_1 = new RelayCommand<object>(DoCommand20T_1);
            Command20T_2 = new RelayCommand<object>(DoCommand20T_2);
            Command20T_3 = new RelayCommand<object>(DoCommand20T_3);
            Command20T_4 = new RelayCommand<object>(DoCommand20T_4);
            Command20T_5 = new RelayCommand<object>(DoCommand20T_5);
            Command20T_6 = new RelayCommand<object>(DoCommand20T_6);
            Command20T_7 = new RelayCommand<object>(DoCommand20T_7);
            Command20T_8 = new RelayCommand<object>(DoCommand20T_8);
            CommandZB_1 = new RelayCommand<object>(DoCommandZB_1);
            CommandZB_2 = new RelayCommand<object>(DoCommandZB_2);             
            CommandZCB_1 = new RelayCommand<object>(DoCommandZCB_1);
            CommandZCB_2 = new RelayCommand<object>(DoCommandZCB_2);
            CommandDNBC_1 = new RelayCommand<object>(DoCommandDNBC_1);
            CommandDNBC_2 = new RelayCommand<object>(DoCommandDNBC_2);
            CommandDNBC_3 = new RelayCommand<object>(DoCommandDNBC_3);
            CommandDNBC_4 = new RelayCommand<object>(DoCommandDNBC_4);
            CommandDK_1 = new RelayCommand<object>(DoCommandDK_1);
            CommandDK_2 = new RelayCommand<object>(DoCommandDK_2);
            CommandQF_1 = new RelayCommand<object>(DoCommandQF_1);
            CommandQF_2 = new RelayCommand<object>(DoCommandQF_2);
            CommandQF_3 = new RelayCommand<object>(DoCommandQF_3);
            CommandQF_4 = new RelayCommand<object>(DoCommandQF_4);
            CommandQF_5 = new RelayCommand<object>(DoCommandQF_5);
            CommandQF_6 = new RelayCommand<object>(DoCommandQF_6);
            
            CommandGW1_1 = new RelayCommand<object>(DoCommandGW1_1);
            CommandGW1_2 = new RelayCommand<object>(DoCommandGW1_2);
            CommandGW1_3 = new RelayCommand<object>(DoCommandGW1_3);
            CommandGW1_4 = new RelayCommand<object>(DoCommandGW1_4);
            CommandGW2_1 = new RelayCommand<object>(DoCommandGW2_1);
            CommandGW2_2 = new RelayCommand<object>(DoCommandGW2_2);
            CommandGW2_3 = new RelayCommand<object>(DoCommandGW2_3);
            CommandGW2_4 = new RelayCommand<object>(DoCommandGW2_4);
            CommandGW3_1 = new RelayCommand<object>(DoCommandGW3_1);
            CommandGW3_2 = new RelayCommand<object>(DoCommandGW3_2);
            CommandGW3_3 = new RelayCommand<object>(DoCommandGW3_3);
            CommandGW3_4 = new RelayCommand<object>(DoCommandGW3_4);

            //初始化后台线程...-- 这里不能直接调用，因为resources还是NULL的..
            //InitializeAsync();
            //AddRecord((string)resources["PLCMessage18"], false);
            //AddRecord("启动完成...",false);        
        }
        
        public byte[]? aidian { get; set; } = null;

        public void MainClose()
        {
            if (rotobTaskT != null)
            {
                cts.Cancel();
            }
        }

        void DoPlcCommand(string command, bool data)
        {
            //这里等待了... (主线程还是等了..)
            if (queue.Count >= 1)
            {
                AddRecord((string)resources["PLCMessage17"], true);
                //AddRecord("无法执行指令,上一条指令还未执行完成", true);
                return;
            }
            queue.Enqueue(new BKCommand { Command = command, Data = data });
        }


        private ushort[] ReadModbusData(byte slaveId, ushort start, ushort length)
        {
            float[] FloatValue = new float[3];
            try
            {
                //这里我懂了，这里多此一举了.. 本质读取的是WORD 2个字的，可是我自己又转变成了BYTE了...
                ushort[] data = this.master.ReadHoldingRegisters(slaveId, start, length);

                //这里肯定要转REAL。。。

                /*
                byte[] _cbuffer = new byte[4];

                if (startAddress == 0)
                {
                    if (numberOfPoints == 2)
                    {
                        Buffer.BlockCopy(registerBuffer, 0, _cbuffer, 0, 4);
                        //数值翻转得到大端模式... Array.Reverse(_cbuffer);
                        FloatValue[0] = BitConverter.ToSingle(_cbuffer, 0);
                        FloatValue[1] = BitConverter.ToSingle(_cbuffer, 0);
                        FloatValue[2] = BitConverter.ToSingle(_cbuffer, 0);
                    }
                }
                */
                return data;
            }
            catch (Exception ex)
            {
                throw;
            }            
        }

        public bool[] alldian_bool { get; set; } = new bool[300];

        void ByteToBool(byte[] alldian)
        {
            int k = 0;
            //取PLC O-0 2000中频机
            for (int i = 0; i < 8; i++, k++)
            {
                bool value = Bit.FromByte(alldian[0], (byte)i);
                alldian_bool[k] = value;
            }

            //取PLC O-0 2000中频机
            for (int i = 0; i < 8; i++, k++)
            {
                bool value = Bit.FromByte(alldian[1], (byte)i);
                alldian_bool[k] = value;
            }

            //取PLC O-8
            for (int i = 0; i < 8; i++, k++)
            {
                bool value = Bit.FromByte(alldian[8], (byte)i);
                alldian_bool[k] = value;
            }

            //取PLC O-9
            for (int i = 0; i < 8; i++, k++)
            {
                bool value = Bit.FromByte(alldian[9], (byte)i);
                alldian_bool[k] = value;
            }

            //取PLC O-12
            for (int i = 0; i < 8; i++, k++)
            {
                bool value = Bit.FromByte(alldian[12], (byte)i);
                alldian_bool[k] = value;
            }

            //取PLC O-13
            for (int i = 0; i < 8; i++, k++)
            {
                bool value = Bit.FromByte(alldian[13], (byte)i);
                alldian_bool[k] = value;
            }

            //取PLC O-16
            for (int i = 0; i < 8; i++, k++)
            {
                bool value = Bit.FromByte(alldian[16], (byte)i);
                alldian_bool[k] = value;
            }

            //取PLC O-17
            for (int i = 0; i < 8; i++, k++)
            {
                bool value = Bit.FromByte(alldian[17], (byte)i);
                alldian_bool[k] = value;
            }

        }

        // 更新数据库中的数据
        void SendDataToDataBase()
        {
            //这里必须是这样，因为数据库是FLOAT，如果直接插入就一大堆小数点.. 这里必须我来保留3位.
            //还有，数据库里面是FLOAT，可是我C#里面必须是double 才能对应..--这里必须 Math.Round 要不然，数据库肯定小数点多...
            //因为我是PC端，所以可以不通过WEB 服务器.. 直接去写数据库..
            my_table temp_info = new my_table();
            Random random = new Random();
            // 例如，在[10, 20]范围内生成浮点数
            float randomFloatInRange1 = (float)(10 + random.NextDouble() * 10);
            float randomFloatInRange2 = (float)(10 + random.NextDouble() * 10);
            float randomFloatInRange3 = (float)(10 + random.NextDouble() * 10);            
            temp_info.ab = (double)Math.Round(randomFloatInRange1, 3);             
            temp_info.bc = (double)Math.Round(randomFloatInRange2, 3);            
            temp_info.ca = (double)Math.Round(randomFloatInRange3, 3);

            
            try
            {
                using (var context = new MyDbContext())
                {
                    //如果ID设置为0 就是添加.. 如果是指定ID就是修改了.
                    //temp_info.id = 0;
                    temp_info.id = 1;
                    //这里不能调用Add --- 如果调用了，就是添加了..
                    //这里必须使用UPDATE-- 更新..
                    context.zhongbianshurudianya_table.Update(temp_info);

                    // 更新已有数据(这里必须先搜索一次吗？--必须先搜索--要不然他不更新..)
                    //var person = context.zhongbianshurudianya_table.Find(temp_info.id);
                    var person = new my_table();

                    if (person != null)
                    {
                        //注意这里不是比较，是赋值了..(后面的数据给前面的.. )
                        ObjectComparer.CompareObjects(person, temp_info);
                    }
                    //context.SaveChanges();
                    int rowsAffected = context.SaveChanges();
                    if (rowsAffected > 0)
                    {
                        AddRecord((string)resources["MyMessage40"], false);
                    }
                    else
                    {
                        AddRecord((string)resources["MyMessage41"], false);
                    }
                }
            }
            catch (Exception ex)
            {
                throw;
            }            
        }

        void ReadAllPlcData()
        {
            try
            {
                //读表.
                ushort[] data = ReadModbusData(1,0,10);

                //读PLC41 0--1.7(16) -- 一次读取主机所有O点..
                ByteToBool(plc31.ReadBytes(DataType.Output, 0, 0, 18));

                aidian = plc31.ReadBytes(DataType.DataBlock, 2, 0, 2);

                //更新界面上显示的调压数字....
                mainModel.Ai_data = aidian[1];

                //更新表(6个表)
                mainModel.Biao1_data1 = data[0];
                mainModel.Biao1_data2 = data[1];
                mainModel.Biao1_data3 = data[2];

                mainModel.Biao2_data1 = data[3];
                mainModel.Biao2_data2 = data[4];
                mainModel.Biao2_data3 = data[5];

                //更新界面--更新门闸..
                WeakReferenceMessenger.Default.Send<string, string>("ShowAllPlcDian", "SWaitchXZ");

                //发送数据到数据库(需要吗？)
                SendDataToDataBase();

            }
            catch (Exception ex)
            {
                throw;
            }
        }

        //检查是不是断线..
        bool ScanConntion()
        {
            
            if (!plc31.IsConnected)
            {
                //AddRecord("PLC-31主机断线,请检查PLC链接是否正常...", true);
                AddRecord((string)resources["PLCMessage12"], false);
                mainModel.Plc31 = false;//设置红灯
                return false;
            }
            if (!plc33.IsConnected)
            {
                //AddRecord("PLC-33从机断线,请检查PLC链接是否正常...", true);
                AddRecord((string)resources["PLCMessage13"], false);
                mainModel.Plc33 = false; //设置红灯
                return false;
            }
            if (!plc35.IsConnected)
            {
                //AddRecord("PLC-35从机断线,请检查PLC链接是否正常...", true);
                AddRecord((string)resources["PLCMessage14"], false);
                mainModel.Plc35 = false; //设置红灯
                return false;
            }
            if (!plc37.IsConnected)
            {

                //AddRecord("PLC-37从机断线,请检查PLC链接是否正常...", true);
                AddRecord((string)resources["PLCMessage15"], false);
                mainModel.Plc37 = false; //设置红灯
                return false;
            }
            mainModel.Plc31 = true; //设置绿灯
            mainModel.Plc33 = true;//设置绿灯
            mainModel.Plc35 = true; //设置绿灯
            mainModel.Plc37 = true;//设置绿灯
            return true;            
        }

        private void DoCommand75_1(object button) { DoPlcCommand("DoCommand75_1", true); return;}        
        private void DoCommand75_2(object button) { DoPlcCommand("DoCommand75_2", true); return;}        
        private void DoCommand75_3(object button) { DoPlcCommand("DoCommand75_3", true); return; }
        private void DoCommand75_4(object button) { DoPlcCommand("DoCommand75_4", true); return; }
        private void DoCommand75_5(object button) 
        {
            //这里有个问题，这里，我无法修改数值，因为 -- 数值是从 AI读过来的.. 不停的在读...
            DoPlcCommand("DoCommand75_5", true); return; 
        }
        private void DoCommand75_6(object button) { DoPlcCommand("DoCommand75_6", true); return; }
        private void DoCommand20_1(object button) { DoPlcCommand("DoCommand20_1", true); return; }
        private void DoCommand20_2(object button) { DoPlcCommand("DoCommand20_2", true); return; }
        private void DoCommand20_3(object button) { DoPlcCommand("DoCommand20_3", true); return; }
        private void DoCommand20_4(object button) { DoPlcCommand("DoCommand20_4", true); return; }
        private void DoCommand20_5(object button) { DoPlcCommand("DoCommand20_5", true); return; }
        private void DoCommand20_6(object button) { DoPlcCommand("DoCommand20_6", true); return; }
        private void DoCommand20T_1(object button) { DoPlcCommand("DoCommand20T_1", true); return; }
        private void DoCommand20T_2(object button) { DoPlcCommand("DoCommand20T_2", true); return; }
        private void DoCommand20T_3(object button) { DoPlcCommand("DoCommand20T_3", true); return; }
        private void DoCommand20T_4(object button) { DoPlcCommand("DoCommand20T_4", true); return; }
        private void DoCommand20T_5(object button) { DoPlcCommand("DoCommand20T_5", true); return; }
        private void DoCommand20T_6(object button) { DoPlcCommand("DoCommand20T_6", true); return; }
        private void DoCommand20T_7(object button) { DoPlcCommand("DoCommand20T_7", true); return; }
        private void DoCommand20T_8(object button) { DoPlcCommand("DoCommand20T_8", false); return; }

        private void DoCommandZB_1(object button) { DoPlcCommand("DoCommandZB_1", true); return; }
        private void DoCommandZB_2(object button) { DoPlcCommand("DoCommandZB_2", true); return; }
        private void DoCommandZCB_1(object button) { DoPlcCommand("DoCommandZCB_1", true); return; }
        private void DoCommandZCB_2(object button) { DoPlcCommand("DoCommandZCB_2", true); return; }
        private void DoCommandDNBC_1(object button) { DoPlcCommand("DoCommandDNBC_1", true); return; }
        private void DoCommandDNBC_2(object button) { DoPlcCommand("DoCommandDNBC_2", true); return; }
        private void DoCommandDNBC_3(object button) { DoPlcCommand("DoCommandDNBC_3", true); return; }
        private void DoCommandDNBC_4(object button) { DoPlcCommand("DoCommandDNBC_4", true); return; }
        private void DoCommandDK_1(object button) { DoPlcCommand("DoCommandDK_1", true); return; }
        private void DoCommandDK_2(object button) { DoPlcCommand("DoCommandDK_2", true); return; }
        private void DoCommandQF_1(object button) { DoPlcCommand("DoCommandQF_1", true); return; }
        private void DoCommandQF_2(object button) { DoPlcCommand("DoCommandQF_2", true); return; }
        private void DoCommandQF_3(object button) { DoPlcCommand("DoCommandQF_3", true); return; }
        private void DoCommandQF_4(object button) { DoPlcCommand("DoCommandQF_4", true); return; }
        private void DoCommandQF_5(object button) { DoPlcCommand("DoCommandQF_5", true); return; }
        private void DoCommandQF_6(object button) { DoPlcCommand("DoCommandQF_6", true); return; }

        private void DoCommandGW1_1(object button) { DoPlcCommand("DoCommandGW1_1", true); return; }
        private void DoCommandGW1_2(object button) { DoPlcCommand("DoCommandGW1_2", true); return; }
        private void DoCommandGW1_3(object button) { DoPlcCommand("DoCommandGW1_3", true); return; }
        private void DoCommandGW1_4(object button) { DoPlcCommand("DoCommandGW1_4", true); return; }
        private void DoCommandGW2_1(object button) { DoPlcCommand("DoCommandGW2_1", true); return; }
        private void DoCommandGW2_2(object button) { DoPlcCommand("DoCommandGW2_2", true); return; }
        private void DoCommandGW2_3(object button) { DoPlcCommand("DoCommandGW2_3", true); return; }
        private void DoCommandGW2_4(object button) { DoPlcCommand("DoCommandGW2_4", true); return; }
        private void DoCommandGW3_1(object button) { DoPlcCommand("DoCommandGW3_1", true); return; }
        private void DoCommandGW3_2(object button) { DoPlcCommand("DoCommandGW3_2", true); return; }
        private void DoCommandGW3_3(object button) { DoPlcCommand("DoCommandGW3_3", true); return; }
        private void DoCommandGW3_4(object button) { DoPlcCommand("DoCommandGW3_4", true); return; }

        private async Task<bool> ExePlcCommand(string command, bool data, int isBackCall = 0)
        {                    
            bool Success = false;
            string error = string.Empty;

            //var dynamicBrush = (SolidColorBrush)this.FindResource("DynamicBrush");
            //if (isBackCall == 0) AddRecord("请等待,PLC回应!", false);
            if (isBackCall == 0) AddRecord((string)resources["PLCMessage1"], false);
            var timeout = Task.Delay(8000);
            var t = Task.Run(async () =>
            {
                logger.Debug("新线程-开始执行" + command);
                try
                {
                    if (command != "33" && command != "34" && command != "35" && command != "36") { if (!ScanConntion()) {  Success = false;  return;}}
                    if (command == "33") plc31.Open();                        
                    if (command == "34") plc33.Open();
                    if (command == "35") plc35.Open();
                    if (command == "36") plc37.Open();                        
                    if (command == "500") ReadAllPlcData();

                    switch (command)
                    {

                        case "DoCommand75_1": plc31.Write("M21.3", true); Thread.Sleep(300); plc31.Write("M21.3", false); break;
                        case "DoCommand75_2": plc31.Write("M21.4", true); Thread.Sleep(300); plc31.Write("M21.4", false); break;
                        case "DoCommand75_3": plc31.Write("M21.5", true); Thread.Sleep(300); plc31.Write("M21.5", false); break;
                        case "DoCommand75_4": plc31.Write("M21.6", true); Thread.Sleep(300); plc31.Write("M21.6", false); break;
                        case "DoCommand75_5": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommand75_6": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommand20_1": plc31.Write("M20.3", true); Thread.Sleep(300); plc31.Write("M20.3", false); break;
                        case "DoCommand20_2": plc31.Write("M20.4", true); Thread.Sleep(300); plc31.Write("M20.4", false); break;
                        case "DoCommand20_3": plc31.Write("M20.5", true); Thread.Sleep(300); plc31.Write("M20.5", false); break;
                        case "DoCommand20_4": plc31.Write("M20.6", true); Thread.Sleep(300); plc31.Write("M20.6", false); break;
                        case "DoCommand20_5": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommand20_6": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommand20T_1": plc31.Write("M22.0", true); Thread.Sleep(300); plc31.Write("M22.0", false); break;
                        case "DoCommand20T_2": plc31.Write("M22.1", true); Thread.Sleep(300); plc31.Write("M22.1", false); break;
                        case "DoCommand20T_3": plc31.Write("M22.2", true); Thread.Sleep(300); plc31.Write("M22.2", false); break;
                        case "DoCommand20T_4": plc31.Write("M22.3", true); Thread.Sleep(300); plc31.Write("M22.3", false); break;
                        case "DoCommand20T_5": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommand20T_6": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommand20T_7": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommand20T_8": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommandZB_1": plc31.Write("M30.6", true); Thread.Sleep(300); plc31.Write("M30.6", false); break;
                        case "DoCommandZB_2": plc31.Write("M30.7", true); Thread.Sleep(300); plc31.Write("M30.7", false); break;
                        case "DoCommandZCB_1": plc31.Write("M32.4", true); Thread.Sleep(300); plc31.Write("M32.4", false); break;
                        case "DoCommandZCB_2": plc31.Write("M32.5", true); Thread.Sleep(300); plc31.Write("M32.5", false); break;
                        case "DoCommandDNBC_1": plc31.Write("M32.0", true); Thread.Sleep(300); plc31.Write("M32.0", false); break;
                        case "DoCommandDNBC_2": plc31.Write("M32.1", true); Thread.Sleep(300); plc31.Write("M32.1", false); break;
                        case "DoCommandDNBC_3": plc31.Write("M32.2", true); Thread.Sleep(300); plc31.Write("M32.2", false); break;
                        case "DoCommandDNBC_4": plc31.Write("M32.3", true); Thread.Sleep(300); plc31.Write("M32.3", false); break;
                        case "DoCommandDK_1": plc31.Write("M31.0", true); Thread.Sleep(300); plc31.Write("M31.0", false); break;
                        case "DoCommandDK_2": plc31.Write("M31.1", true); Thread.Sleep(300); plc31.Write("M31.1", false); break;
                        case "DoCommandQF_1": plc31.Write("M31.2", true); Thread.Sleep(300); plc31.Write("M31.2", false); break;
                        case "DoCommandQF_2": plc31.Write("M31.3", true); Thread.Sleep(300); plc31.Write("M31.3", false); break;
                        case "DoCommandQF_3": plc31.Write("M31.4", true); Thread.Sleep(300); plc31.Write("M31.4", false); break;
                        case "DoCommandQF_4": plc31.Write("M31.5", true); Thread.Sleep(300); plc31.Write("M31.5", false); break;
                        case "DoCommandQF_5": plc31.Write("M31.6", true); Thread.Sleep(300); plc31.Write("M31.6", false); break;
                        case "DoCommandQF_6": plc31.Write("M31.7", true); Thread.Sleep(300); plc31.Write("M31.7", false); break;
                        case "DoCommandGW1_1": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommandGW1_2": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommandGW1_3": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommandGW1_4": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommandGW2_1": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommandGW2_2": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommandGW2_3": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommandGW2_4": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommandGW3_1": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommandGW3_2": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommandGW3_3": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                        case "DoCommandGW3_4": plc31.Write("M100.0", true); Thread.Sleep(300); plc31.Write("M100.0", false); break;
                    }
                    Success = true;
                    logger.Debug("新线程-执行完成结束" + command);
                }
                catch (Exception ex)
                {
                    error = ex.Message;
                    AddRecord((string)resources["PLCMessage2"] + error, true);
                    logger.Error("新线程-任务执行异常:" + error);
                    //AddRecord("PLC异常:" + error, true);
                    Success = false;
                }
            });
            //这里有个问题，就是主线程现在在这里等着...
            var completedTask = await Task.WhenAny(timeout, t);
            if (completedTask == timeout)
            {
                AddRecord((string)resources["PLCMessage3"], true);
                logger.Error("机器人线程-超时" + command);
                //AddRecord("PLC超时,请检查PLC是否正常!", true);                
                return false;
            }

            if (Success)
            {
                logger.Debug("机器人线程-完成" + command);
                return true;
            }
            else
            {
                AddRecord((string)resources["PLCMessage2"], true);
                logger.Error("机器人线程-错误Success==false" + command);
                //AddRecord("PLC异常:" + error, true);             
                return false;
            }
        }
            
        

        void AddRecord(string strdata,bool e)
        {            
            string time = System.DateTime.Now.ToString("HH:mm:ss");
            string str = time + "=>" + strdata;
            Application.Current.Dispatcher.Invoke(() =>
            {                
                ListBoxData.Add(new Item { Text = str, IsRed = e });
            });
            WeakReferenceMessenger.Default.Send<string, string>("ScrollEnd", "ScrollEnd");            
        }

        public async void InitializeAsync()
        {
            //先打开端口...
            try
            {
                //TCP也OK了...
                TcpClient tcpClient = new TcpClient();
                tcpClient.Connect(IPAddress.Parse("127.0.0.1"), 502);
                master=ModbusIpMaster.CreateIp(tcpClient);
                master.Transport.WriteTimeout = 2000;
                master.Transport.ReadTimeout = 2000;
                master.Transport.WaitToRetryMilliseconds = 500;
                master.Transport.Retries = 3;

                /*
                AddRecord((string)resources["PLCMessage18"], false);
                logger.Debug("启动完成");
                //AddRecord("启动完成...", false);

                serialPort.BaudRate = 9600; // 设置波特率
                serialPort.Parity = Parity.None; // 设置奇偶校验
                serialPort.DataBits = 8; // 设置数据位数
                serialPort.StopBits = StopBits.One; // 设置停止位
                serialPort.Handshake = Handshake.None; // 设置握手协议

                ModbusIpMaster.CreateIp()
                master = ModbusSerialMaster.CreateRtu(serialPort);//这里传入的就是我们创建的串口对象
                master.Transport.ReadTimeout = 500;// 设置超时时间默认为500毫秒
                serialPort.PortName = ConfigurationManager.AppSettings["DEVICE_COM"];
                serialPort.Open(); //打开串口                
                AddRecord((string)resources["PLCMessage4"], false);

                */
                //AddRecord("打开串口完成",false);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return;
            }

            rotobTaskT = Task.Run(async () =>
            {
                System.DateTime? precurrentTime = System.DateTime.UtcNow;
                TimeSpan? timeSpan = null;

                logger.Debug("机器人线程-初始化链接33");
                var myresult3 = await ExePlcCommand("33", true);
                //if (!myresult3) { AddRecord("连接PLC主机失败-后台线程退出,PLC正常后请重新启动软件!", true); return; }
                if (!myresult3) { AddRecord((string)resources["PLCMessage5"], true); return; }
                //AddRecord("连接PLC主机成功", false);
                AddRecord((string)resources["PLCMessage6"], false);

                logger.Debug("机器人线程-初始化链接34");
                myresult3 = await ExePlcCommand("34", true);
                //if (!myresult3) { AddRecord("连接PLC从机失败-后台线程退出,PLC正常后请重新启动软件!", true); return; }
                if (!myresult3) { AddRecord((string)resources["PLCMessage7"], true); return; }
                //AddRecord("连接PLC从机成功", false);
                AddRecord((string)resources["PLCMessage8"], false);

                logger.Debug("机器人线程-初始化链接35");
                myresult3 = await ExePlcCommand("35", true);
                //if (!myresult3) { AddRecord("连接PLC主机失败-后台线程退出,PLC正常后请重新启动软件!", true); return; }
                if (!myresult3) { AddRecord((string)resources["PLCMessage7"], true); return; }
                //AddRecord("连接PLC从机成功", false);
                AddRecord((string)resources["PLCMessage8"], false);

                logger.Debug("机器人线程-初始化链接36");
                myresult3 = await ExePlcCommand("36", true);
                //if (!myresult3) { AddRecord("连接PLC从机失败-后台线程退出,PLC正常后请重新启动软件!", true); return; }
                if (!myresult3) { AddRecord((string)resources["PLCMessage7"], true); return; }
                //AddRecord("连接PLC从机成功", false);
                AddRecord((string)resources["PLCMessage8"], false);

                
                while (!cts.IsCancellationRequested)
                {
                    try
                    {
                        //这里是需要TRY的。。 我执行代码的时候，遇到了一个问题，就是主线程没有加线程分发.. 导致.. 报错..
                        Thread.Sleep(10);
                        System.DateTime currentTime = System.DateTime.UtcNow;

                        TimeSpan ts = (TimeSpan)(currentTime - precurrentTime);
                        //得到毫秒数...
                        double milliseconds = ts.TotalMilliseconds;
                        
                        //定时时间到了..
                        if (milliseconds > 1000)
                        {
                            logger.Debug("机器人线程-定时器1秒任务");
                            //设置为后台执行..
                            var myresult1 = await ExePlcCommand("500", true,1 );
                            //必须要判断，要不然 子线程他不等..
                            if (!myresult1)
                            {
                                AddRecord((string)resources["PLCMessage9"], true);
                                //AddRecord("定时器指令读取PLC执行失败-后台线程退出!", true);
                                return;
                            }
                            precurrentTime = currentTime;
                            continue;
                        }
                        if (queue.Count <= 0) continue;
                        BKCommand Command = queue.Dequeue();
                        logger.Debug("机器人线程-点击" + Command.Command);
                        var myresult2 = await ExePlcCommand(Command.Command, Command.Data);
                        if (myresult2)
                        {
                            AddRecord((string)resources["PLCMessage10"], false);
                            //AddRecord("指令执行成功!", false);
                        }
                        else
                        {
                            AddRecord((string)resources["PLCMessage11"], true);
                            //AddRecord("指令执行失败!-后台线程退出", true);
                            return;
                        }

                    }
                    catch (Exception ex)
                    {
                        AddRecord($"{ex.Message}", true);
                        logger.Error("机器人线程报错"+ ex.Message);
                        return;
                    }
                }
            }, cts.Token);
        }


    }

    public class Item
    {
        public string Text { get; set; }
        public bool IsRed { get; set; }
    }

    public class BKCommand
    {
        public string Command { get; set; } = string.Empty;
        public bool Data { get; set; } = false;
    }
}
